package xyz.robinbingo.rbtask.web.handler;

import cn.hutool.core.exceptions.ExceptionUtil;
import cn.hutool.json.JSONUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.HttpMethod;
import org.springframework.http.converter.HttpMessageNotReadableException;
import org.springframework.validation.BindException;
import org.springframework.web.HttpRequestMethodNotSupportedException;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.MissingServletRequestParameterException;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
import xyz.robinbingo.rbtask.common.bean.ResResult;
import xyz.robinbingo.rbtask.common.enums.ResEnum;
import xyz.robinbingo.rbtask.common.exception.CustomException;

import javax.servlet.http.HttpServletRequest;

/**
 * GlobalExceptionHandler
 *
 * @author Robin
 * @date 2018/8/1 14:26
 **/
@ControllerAdvice
@Slf4j
public class GlobalExceptionHandler {

    @Value("${spring.application.name")
    private String appName;

    /**
     * 处理非logAspect中的异常
     *
     * @param e       e
     * @param request request
     * @return BaseRes
     * @author Robin
     * @date 2020/9/2 17:00
     **/
    @ExceptionHandler
    @ResponseBody
    public ResResult<Void> handleException(Exception e, HttpServletRequest request) {

        String uri = request.getRequestURI();
        // TODO-Robin: 2021/3/25 post data
        String param = "unknown";
        if (HttpMethod.GET.matches(request.getMethod())) {
            param = JSONUtil.toJsonStr(request.getParameterMap());
        }

        Integer code;
        String message;
        String errInfo = null;
        if (e instanceof HttpRequestMethodNotSupportedException) {
            // 不支持的请求类型
            code = ResEnum.ILLEGAL_REQUEST_METHOD.getCode();
            String method = ((HttpRequestMethodNotSupportedException) e).getMethod();
            message = ResEnum.ILLEGAL_REQUEST_METHOD.getMessage() + ":" + method;
        } else if (e instanceof HttpMessageNotReadableException) {
            // 请求参数格式有误
            code = ResEnum.ARGUMENT_NOT_READABLE.getCode();
            message = ResEnum.ARGUMENT_NOT_READABLE.getMessage();
        } else if (e instanceof MethodArgumentNotValidException) {
            // validation 异常
            code = ResEnum.ILLEGAL_ARGUMENT.getCode();
            message = ((MethodArgumentNotValidException) e).getBindingResult().getAllErrors().get(0).getDefaultMessage();
        } else if (e instanceof BindException) {
            // validation 异常
            code = ResEnum.ILLEGAL_ARGUMENT.getCode();
            message = ((BindException) e).getBindingResult().getAllErrors().get(0).getDefaultMessage();
        } else if (e instanceof MissingServletRequestParameterException) {
            // 缺少请求参数
            code = ResEnum.MISSING_PARAM.getCode();
            String parameterName = ((MissingServletRequestParameterException) e).getParameterName();
            message = ResEnum.MISSING_PARAM.getMessage() + ":" + parameterName;
        } else if (e instanceof CustomException) {
            // 自定义异常
            code = ((CustomException) e).getCode();
            message = e.getMessage();
        } else {
            // 未知异常
            code = ResEnum.FAIL.getCode();
            message = ResEnum.FAIL.getMessage();
            errInfo = ExceptionUtil.stacktraceToString(e);
        }
        if (errInfo == null) {
            errInfo = code + ":" + message;
        }
        log.error("[" + appName + "-err]:uri=[{}], req=[{}], error=[{}]", uri, param, errInfo);
        return ResResult.fail(code, message);
    }
}